package com.maistars.spider.controller;

import cn.hutool.core.date.DateUtil;
import com.maistars.spider.repository.security.model.UserPO;
import com.maistars.spider.security.service.UserService;
import com.maistars.spider.view.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * @author dhr
 * @date 2022/7/2 22:24
 */
@Controller
@Slf4j
public class UserController {

    @Autowired
    private UserService userService;

    @Autowired
    private SessionDAO sessionDAO;

    @GetMapping("/user/showLogin")
    public String login() {
        return "user/login";
    }

    @GetMapping("/user/showForget")
    public String forget() {
        return "user/forget";
    }

    @GetMapping("/user/showReg")
    public String reg() {
        return "user/reg";
    }

    @RequestMapping("/user/createUser")
    @ResponseBody
    public ResponseResult<Boolean> createUser(HttpServletRequest request){
        ResponseResult<Boolean> responseResult = new ResponseResult<Boolean>();
        responseResult.setCode(100);

        String phone = request.getParameter("cellphone");
        String verCode = request.getParameter("vercode");
        String password = request.getParameter("password");
        String repassword = request.getParameter("repassword");
        String nickName = request.getParameter("nickname");

        UserPO userPO = new UserPO();
        userPO.setPhone(phone);
        userPO.setNickName(nickName);

        HttpSession session = request.getSession();
		/*String randomString = vercode.toUpperCase();
		if (!session.getAttribute("randomString").equals(randomString)) {
			String result = "{\"status\":1,\"msg\":\"验证码出错！请检查。"+session.getAttribute("randomString")+"}";
			return result;
		}*/
        if (!password.equals(repassword)) {
            responseResult.setCode(200);
            responseResult.setMsg("密码不一致");
            return responseResult;
        }
        if (userService.getUserByPhone(phone) != null) {
            responseResult.setCode(200);
            responseResult.setMsg("注册账号失败，原因：电话号码重复");
            return responseResult;
        }

        userPO.setPassword(new SimpleHash("MD5", password).toString());
        // 默认账号为电话号码
        userPO.setUsername(phone);
        userPO.setCreateTime(new Date());
        userPO.setLocked(0);
        userPO.setStatus(0);
        userPO.setNickName(nickName);
        userPO.setPhone(phone);

        userService.addUser(userPO);
        userPO = userService.getUserByUsername(phone);
        int[] roleIds = {2};
        for (Integer roleId : roleIds) {
            userService.addUserRole(userPO.getUserId(), roleId);
        }
        responseResult.setData(true);
        return responseResult;
    }

    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
    @ResponseBody
    public String login(@RequestParam(value = "username") String username,
                        @RequestParam(value = "password") String password,
                        @RequestParam(value = "vercode") String captcha,
                        HttpServletRequest request, HttpServletResponse response, Model model) {
        HttpSession session = request.getSession();
        String randomString = captcha.toUpperCase();
        String msg = null;
        UserPO user = new UserPO();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        try {
            if (!session.getAttribute("randomString").equals(randomString)) {
                msg = "验证码出错！请检查。";
                model.addAttribute("message", msg);
                String result = "{\"success\":false,\"msg\":\"验证码出错！请检查。\"}";
                return result;
            }

            //默认记住我
            token.setRememberMe(true);
            token.setHost(request.getRemoteAddr());
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);
            msg = "登录成功！登录IP:" + token.getHost();
            user = userService.getUserByUsername(username);
            user.setLastIp(request.getRemoteAddr());
            user.setLastTime(new Date());
            userService.updateUser(user);
            model.addAttribute("message", msg);
            request.getSession().setAttribute("user", user);
            String result = "{\"status\":0,\"msg\":\"" + msg + "。\",\"action\":\"/index\"}";
            log.info("用户" + username + "登录成功，时间：" + DateUtil.formatDateTime(new Date())
            );
            return result;
        } catch (IncorrectCredentialsException e) {
            msg = "帐号" + token.getPrincipal() + "登录密码错误。";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (ExcessiveAttemptsException e) {
            msg = "登录失败次数过多";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (LockedAccountException e) {
            msg = "帐号" + token.getPrincipal() + "已被锁定. ";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (DisabledAccountException e) {
            msg = "帐号" + token.getPrincipal() + "已被禁用";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (ExpiredCredentialsException e) {
            msg = "帐号" + token.getPrincipal() + "已过期";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (UnknownAccountException e) {
            msg = "帐号" + token.getPrincipal() + "不存在";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (UnauthorizedException e) {
            msg = "您没有得到相应的授权！";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (AuthenticationException e) {
            msg = "无此账号，验证错误";
            model.addAttribute("message", msg);
            log.error(msg, e);
        } catch (Exception e) {
            msg = "未知错误";
            model.addAttribute("message", msg);
            log.error(msg, e);
        }

        String result = "{\"status\":false,\"msg\":\"" + msg + "。\"}";
        return result;

    }

    @RequiresUser
    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    public String logout(HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {
        String result = "false";
        String username = "";
        try {
            response.setCharacterEncoding("UTF-8");
            Subject subject = SecurityUtils.getSubject();
            username = (String) subject.getPrincipal();
            subject.logout();
            result = "已成功登出";
        } catch (Exception e) {
            log.error("logout()", e);
            result = "登出发生异常";
        }
        log.info("用户" + username + result + DateUtil.formatDateTime(new Date()));
        return "redirect:/?logout=1";
    }

    @RequestMapping("/{sessionId}/forceLogout")
    @ResponseBody
    public String forceLogout(@PathVariable("sessionId") String sessionId,
                              RedirectAttributes redirectAttributes) {
        try {
            Session session = sessionDAO.readSession(sessionId);
            if (session != null) {
                session.setAttribute(
                        "LOGOUT", Boolean.TRUE);
            }
        } catch (Exception e) {/*ignore*/}
        /*redirectAttributes.addAttribute("forcelogout", "1");  //重定向携带的参数
        return "redirect:/login";  */
        return "success";
    }

    @RequestMapping(value = "getSessionId", method = RequestMethod.GET, produces = "text/html;charset=utf-8")
    @ResponseBody
    public Serializable getSessionId(HttpServletRequest request, HttpServletResponse response) {
        Cookie[] cookies = request.getCookies();
        String sid = null;
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals("sid")) {
                sid = cookie.getValue();
                cookie.setMaxAge(-1);
            }
        }
        Session session = sessionDAO.readSession(sid);
        //session.setAttribute("LOGOUT", Boolean.TRUE);
        return sid + ":" + sessionDAO.toString() + ":" + session.toString();
    }

    @RequestMapping(value = "getSessionList", method = RequestMethod.GET, produces = "text/html;charset=utf-8")
    public String getSessionList(HttpServletRequest request, HttpServletResponse response, Model model) {
        Collection<Session> sessions = sessionDAO.getActiveSessions();//取出来的集合中除了session，还有linkedList,直接遍历会报异常
        String s = sessions.toString();
        String[] sids = s.split(",");//转换成字符串之后再根据“,”,分组，再根据id查找对应session放到集合中去
        List<Session> list = new ArrayList<>();
        Session session = null;
        for (String sid : sids) {
            if (StringUtils.contains(sid, "id=")) {
                try {
                    session = sessionDAO.readSession(sid.substring(3, 39));
                } catch (Exception e) {
                    session = null;
                }
                if (session != null && session.getAttribute("org.apache.shiro.subject.support.DefaultSubjectContext_AUTHENTICATED_SESSION_KEY") != null) {
                    list.add(session);
                }
            }
        }
        model.addAttribute("sessions", list);
        model.addAttribute("sessionCount", list.size());
        return "system/session";
    }

    @ExceptionHandler({Exception.class})
    @ResponseStatus(code = HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public String processUnauthenticatedException(ServletRequest request, ServletResponse response) {

        String result = "{\"status\":1,\"msg\":\"" + "无权" + "。\"}";
        return result;
    }

}
